#include "Area.h"
#include "Game.h"
#include "Scene.h"
#include <tinyxml.h>
#include "PointsLightsManager.h"

Area::Area()
{
	mIsRenderingFlag = false;
	mIsRendering = false;
}

Area::Area(const Area&)
{

}

Area::~Area()
{

}

bool Area::Initialize()
{
	mGame = Game::Instance();
	mPointsLightsManager = mGame->GetShader()->GetPointsLightsManager();
	CalculBoundingBox();
	return true;
}

void Area::InitializeByXml(Scene* pSceneParent, TiXmlElement* areaElement)
{
	mGame = Game::Instance();
	mSceneParent = pSceneParent;

	const char* strId = areaElement->Attribute("id");
	mId = ::atoi(strId);

	
	TiXmlElement* subarea = areaElement->FirstChildElement( "Subarea" );
	for( subarea; subarea; subarea=subarea->NextSiblingElement("Subarea") )
	{
		const char* strSubareaId = subarea->Attribute("id");
		int subareaId = ::atoi(strSubareaId);
		mSubareasId.push_back(subareaId);
	}

	TiXmlElement* linkedArea = areaElement->FirstChildElement( "LinkedArea" );
	for( linkedArea; linkedArea; linkedArea=linkedArea->NextSiblingElement("LinkedArea") )
	{
		const char* strLinkedAreasId = linkedArea->Attribute("id");
		int linkedAreasId = ::atoi(strLinkedAreasId);
		mLinkedAreasId.push_back(linkedAreasId);
	}

	TiXmlElement* entity = areaElement->FirstChildElement( "Entity" );
	for( entity; entity; entity=entity->NextSiblingElement("Entity") )
	{
		Entity* e = new Entity();
		e->InitializeByXml(entity);
		mEntities.push_back(e);
	}
	mBoundingBoxIsCompute = false;

	TiXmlElement* pointLight = areaElement->FirstChildElement( "PointLight" );
	for( pointLight; pointLight; pointLight=pointLight->NextSiblingElement("PointLight") )
	{
		PointLight* p = new PointLight();
		const char* strPosition = pointLight->Attribute("position");
		GetVector3D(strPosition, p->Position);

		XMFLOAT3 color3;
		const char* strColor = pointLight->Attribute("color");
		GetVector3D(strColor, color3);
		p->Color = XMFLOAT4(color3.x,color3.y,color3.z,1);

		const char* strPower = pointLight->Attribute("power");
		p->Power = ::atof(strPower);

		mPointsLightsList.push_back(p);
	}

	mPointsLightsManager = mGame->GetShader()->GetPointsLightsManager();
}

void Area::Link()
{
	for(std::vector<int>::iterator areaId = mSubareasId.begin();areaId != mSubareasId.end();++areaId)
	{
		mSubareas.push_back(mSceneParent->GetAreaById(*areaId));
	}
	for(std::vector<int>::iterator areaId = mLinkedAreasId.begin();areaId != mLinkedAreasId.end();++areaId)
	{
		mLinkedAreas.push_back(mSceneParent->GetAreaById(*areaId));
	}
}

void Area::Uninit()
{

}

void Area::Update(int pElapsedTime)
{
	for(std::vector<Entity*>::iterator entity = mEntities.begin();entity != mEntities.end();++entity)
	{
		(*entity)->Update(pElapsedTime);
	}
}

void Area::PreRender(bool pDoLinkArea)
{
	mIsRenderingFlag = true;
	mSceneParent->AddAreaInRendering(this);

	for(std::vector<Entity*>::iterator entity = mEntities.begin();entity != mEntities.end();++entity)
	{
		(*entity)->PreRender();
	}

	if(pDoLinkArea)
	{
		for(std::vector<Area*>::iterator linkedArea = mLinkedAreas.begin();linkedArea != mLinkedAreas.end();++linkedArea)
		{
			(*linkedArea)->PreRender(false);
		}
	}
}

//void Area::ShadowRender(ShadowMap* pShadowMap)
//{
//	for(std::vector<Entity*>::iterator entity = mEntities.begin();entity != mEntities.end();++entity)
//	{
//		(*entity)->ShadowRender(pShadowMap);
//	}
//
//	for(std::vector<Area*>::iterator linkedArea = mLinkedAreas.begin();linkedArea != mLinkedAreas.end();++linkedArea)
//	{
//		(*linkedArea)->ShadowRender(pShadowMap);
//	}
//}

void Area::Render()
{
	
}

void Area::GetBoundingBox(BoundingBox &pBoundingBox)
{
	if(	!mBoundingBoxIsCompute )
	{
		CalculBoundingBox();
	}
	pBoundingBox = mBoundingBox;
}

void Area::CalculBoundingBox(bool pForce)
{
	if(mBoundingBoxIsCompute && !pForce) return;

	bool first = true;
	BoundingBox tmpBoundingBox;
	for(std::vector<Entity*>::iterator entity = mEntities.begin();entity != mEntities.end();++entity)
	{
		if( first )
		{
			(*entity)->GetBoundingBox(mBoundingBox);
			first = false;
		}
		else
		{
			(*entity)->GetBoundingBox(tmpBoundingBox);
			AddBoundingBox(mBoundingBox, tmpBoundingBox);
		}
	}

	for(std::vector<Area*>::iterator area = mSubareas.begin();area != mSubareas.end();++area)
	{
		if( first )
		{
			(*area)->GetBoundingBox(mBoundingBox);
			first = false;
		}
		else
		{
			(*area)->GetBoundingBox(tmpBoundingBox);
			AddBoundingBox(mBoundingBox, tmpBoundingBox);
		}
	}

	mBoundingBoxIsCompute = true;
}

bool Area::IsInBoundingBox(XMFLOAT3 &position)
{
	 return
   (position.x > mBoundingBox.x1 && position.x < mBoundingBox.x2 &&
    position.y > mBoundingBox.y1 && position.y < mBoundingBox.y2 &&
    position.z > mBoundingBox.z1 && position.z < mBoundingBox.z2);
}

int Area::GetId()
{
	return mId;
}

Area* Area::GetAreaByPosition(XMFLOAT3 &position)
{
	if(IsInBoundingBox(position))
	{
		for(std::vector<Area*>::iterator subarea = mSubareas.begin();subarea != mSubareas.end();++subarea)
		{
			Area* resultArea = (*subarea)->GetAreaByPosition(position);
			if(resultArea != 0)
			{
				return resultArea;
			}
		}
		return this;
	}
	else
	{
		return 0;
	}
}

void Area::EventStartRendering()
{
	for(std::vector<PointLight*>::iterator pointLightIt = mPointsLightsList.begin();pointLightIt != mPointsLightsList.end();++pointLightIt)
	{
		mPointsLightsManager->AddLight(*pointLightIt);
	}

	mIsRendering = true;
}

void Area::EventStopRendering()
{
	for(std::vector<PointLight*>::iterator pointLightIt = mPointsLightsList.begin();pointLightIt != mPointsLightsList.end();++pointLightIt)
	{
		mPointsLightsManager->RemoveLight(*pointLightIt);
	}

	mIsRendering = false;
}

int Area::GetSubAreaCount()
{
	int result = 0;
	for(std::vector<Area*>::iterator subarea = mSubareas.begin();subarea != mSubareas.end();++subarea)
	{
		result += 1 + (*subarea)->GetSubAreaCount();
	}
	return result;
}

bool Area::IsRenderingFlag()
{
	return mIsRenderingFlag;
}

void Area::ResetIsRenderingFlag()
{
	mIsRenderingFlag = false;
}

bool Area::IsRendering()
{
	return mIsRendering;
}